home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Client Developer / Samples / AppleTalk / ADSPSample.cp next >
Encoding:
Text File  |  1998-04-30  |  27.3 KB  |  1,102 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ADSPSample.cp
  3.  
  4.     Contains:    Sample program for the ADSP endpoint
  5.  
  6.     Copyright:    © 1992-1995 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. //
  11. // We want to use the OT 'new' operator, not the standard MPW one, so include
  12. // OpenTptGlobalNew.h first.  This is because we use it at Interrupt time.
  13. //
  14. #ifndef __OPENTPTGLOBALNEW__
  15. #include <OpenTptGlobalNew.h>
  16. #endif
  17. #ifndef __OPENTPTAPPLETALK__
  18. #include <OpenTptAppleTalk.h>
  19. #endif
  20. #ifndef __ATALKSAMPLEUTILS__
  21. #include "ATalkSampleUtils.h"
  22. #endif
  23.  
  24. #ifndef __STDIO__
  25. #include <stdio.h>
  26. #endif
  27. #ifndef __EVENTS__
  28. #include <Events.h>
  29. #endif
  30.  
  31. const size_t kMaxEndpoints    = 3;
  32.  
  33. #define USENBPBIND 1
  34.  
  35. /*******************************************************************************
  36. ** Structures
  37. ********************************************************************************/
  38.  
  39. class TOTEventItem
  40. {
  41.     public:
  42.                     inline TOTEventItem(void* ref, unsigned long code,
  43.                                          OTResult result, void* cookie)
  44.                     {
  45.                         fLink.fNext    = NULL;
  46.                         fRef        = ref;
  47.                         fCode        = code;
  48.                         fResult        = result;
  49.                         fCookie        = cookie;
  50.                     };
  51.     OTLink            fLink;
  52.     void*            fRef;
  53.     unsigned long    fCode;
  54.     OTResult        fResult;
  55.     void*            fCookie;
  56. };
  57.  
  58. struct TTIIEventList
  59. {
  60.     TOTEventItem*    fHead;
  61.     TOTEventItem*    fTail;
  62. };
  63.  
  64. /*******************************************************************************
  65. ** GlobalVariables
  66. ********************************************************************************/
  67.  
  68. OTLIFO            gEventList            = { 0 };
  69. TEndpoint*         gEp[kMaxEndpoints]    = {NULL, NULL, NULL};
  70.  
  71. Boolean            gDoingTearDown = false;
  72.  
  73. const UInt16    kDoBindFlag                = 0x0001;
  74. const UInt16    kDoConnectFlag            = 0x0002;
  75. const UInt16    kDoListenFlag            = 0x0004;
  76. const UInt16    kDoAcceptFlag            = 0x0008;
  77. const UInt16    kDoRejectFlag            = 0x0010;
  78. const UInt16    kDoHandOffFlag            = 0x0020;
  79. const UInt16    kDoSelfSend                = 0x0040;
  80. const UInt16    kDoProtAddrAfterConnect    = 0x0080;
  81. const UInt16    kDoProtAddrAfterBind    = 0x0100;
  82. const UInt16    kSendFlowedFlag            = 0x0200;
  83. const UInt16    kSendExFlowedFlag        = 0x0400;
  84.  
  85. UInt16            gEpFlags[kMaxEndpoints] = {0, 0, 0};
  86. OTResult        gEpStates[kMaxEndpoints] = {-1, -1, -1};
  87.  
  88. DDPAddress        gAddr[2*kMaxEndpoints];    // Who they connect to
  89.  
  90. UInt8            gSendBuf[200];
  91.  
  92. int                gTestNum;
  93.  
  94. UInt32            gByteCtr;
  95. UInt16            gDotCtr;
  96. const UInt32    kBytesPerDot             = 10000;
  97. const UInt16    kDotsPerLine            = 64;
  98.  
  99. /*******************************************************************************
  100. ** Universal event handler...
  101. ********************************************************************************/
  102.  
  103. pascal void UniversalEventHandler(void* contextPtr, OTEventCode code,
  104.                                         OTResult result, void* cookie)
  105. {
  106.     TOTEventItem* item = new TOTEventItem(contextPtr, code, result, cookie);
  107.     if ( item == NULL )
  108.     {
  109.         DebugStr("\pADSPSample: UniversalEventHandler -- could not allocate event structure");
  110.     }
  111.     else
  112.     {
  113.         OTLIFOEnqueue(&gEventList, &item->fLink);    /* Atomically add to list */
  114.     }
  115. }
  116.  
  117. /*******************************************************************************
  118. ** DoSend
  119. ********************************************************************************/
  120.  
  121. static char gTheData[] = "\x01Hello. This is a test of the emergency broadcast system.";
  122.  
  123. OSStatus DoSend(int epNum, Boolean expedited, Boolean more)
  124. {
  125.     TEndpoint* ep = gEp[epNum];
  126.  
  127.     //
  128.     // If we think we're flowed, don't send anything
  129.     //
  130.     if ( gEpFlags[epNum] & (expedited ? kSendExFlowedFlag : kSendFlowedFlag) )
  131.         return 0;
  132.         
  133.  
  134.     gTheData[0] += 1;
  135.         
  136.     OTResult result = ep->Snd(gTheData, sizeof(gTheData), 
  137.                                 ((expedited ? T_EXPEDITED : 0 ) | (more ? T_MORE : 0)));
  138.  
  139.     if ( result == kOTFlowErr )
  140.     {
  141.         fprintf(stderr, "Snd(%d) flow controlled on %s channel\n", epNum,
  142.                     expedited ? "EXPEDITED" : "NORMAL");
  143.         gEpFlags[epNum] |= expedited ? kSendExFlowedFlag : kSendFlowedFlag;
  144.         return kOTNoError;
  145.     }
  146.  
  147.     if ( result == kOTLookErr || result == kOTOutStateErr )
  148.         return kOTNoError;
  149.  
  150.     if ( result < 0 )
  151.     {
  152.         fprintf(stderr, "Snd(%d) fails with %d\n", epNum, result);
  153.     }
  154.     else
  155.         result = kOTNoError;
  156.     return (OSStatus)result;
  157. }
  158.  
  159. /*******************************************************************************
  160. ** DoRead
  161. **
  162. ** Returns kOTNoDataErr if there no data
  163. ********************************************************************************/
  164.  
  165. OSStatus DoRead(int epNum)
  166. {
  167.     TEndpoint*         ep        = gEp[epNum];
  168.     OTFlags            flags    = 0;
  169.     UInt8            buf[200];
  170.     OTResult        result;
  171.  
  172.     while (true)
  173.     {
  174.         result = ep->Rcv(buf, sizeof(buf), &flags);
  175.         if ( result == kOTNoDataErr )
  176.             return kOTNoDataErr;
  177.         if ( result == kOTNoDataErr || result == kOTLookErr ||
  178.              result == kOTOutStateErr )
  179.             return kOTNoError;
  180.         
  181.         if ( result < 0 )
  182.         {
  183.             fprintf(stderr, "Rcv(%d) fails with %d\n", epNum, result);
  184.             return result;
  185.         }
  186.  
  187.     #if 0        
  188.         fprintf(stderr, "Rcv(%d): flags=%08lX; #%d bytes: ", epNum, flags, result);
  189.         if ( result > 10 )
  190.             result = 10;
  191.         
  192.         for ( OTResult i = 0 ; i < result ; i++ )
  193.             fprintf(stderr, "%02x ", buf[i]);
  194.         fprintf(stderr, "\n");
  195.     #else
  196.         gByteCtr += result;
  197.         if ( gByteCtr >= kBytesPerDot )
  198.         {
  199.             gByteCtr -= kBytesPerDot;
  200.             putc('.', stderr);
  201.             if (++gDotCtr >= kDotsPerLine )
  202.             {
  203.                 putc('\n', stderr);
  204.                 gDotCtr = 0;
  205.             }
  206.             fflush(stderr);
  207.         }
  208.                 
  209.     #endif
  210.     }
  211.     
  212.     return kOTNoError;
  213. }
  214.  
  215. #if USENBPBIND
  216. /*******************************************************************************
  217. ** DoBind
  218. ********************************************************************************/
  219.  
  220. OSStatus DoBind(int epNum, int qlen)
  221. {
  222.     char namebuf[64];
  223.     TEndpoint*    ep = gEp[epNum];
  224.     OSStatus    err;
  225.     DDPNBPAddress    myAddress;            // To set up my address for the bind
  226.  
  227.     TBind*        retBind = new TBind;
  228.  
  229.     if ( retBind == NULL )
  230.     {
  231.         DebugStr("\pADSPSample: DoBind, can not allocate TBind.");
  232.         return -1;
  233.     }
  234.     
  235.     sprintf(namebuf, "Test%d%d:ADSPSample", gTestNum, epNum);
  236.     //
  237.     // Initialize my address
  238.     //
  239.     myAddress.Init(0, 0, 0);        // Source address & type
  240.     //
  241.     // Create the TBind for the request, holding my address
  242.     //
  243.     TBind reqBind;
  244.     //
  245.     // Set my name into the NBP address, and init the TBind with
  246.     // the address (SetNBPEntity returns the size of the address).
  247.     //
  248.     reqBind.addr.buf    = (UInt8*)&myAddress;
  249.     reqBind.addr.len    = myAddress.SetNBPEntity(namebuf);
  250.     reqBind.qlen        = qlen;
  251.     
  252.  
  253.     retBind->addr.buf        = (UInt8*)&gAddr[epNum];
  254.     retBind->addr.maxlen    = sizeof(gAddr[epNum]);
  255.     
  256.     fprintf(stderr, "Issuing Bind(%d)\n", epNum);
  257.     err = ep->Bind(&reqBind, retBind);
  258.     if ( err != kOTNoError )
  259.     {
  260.         fprintf(stderr, "Bind(%d) fails with %d\n", epNum, err);
  261.         delete retBind;
  262.     }
  263.     return err;
  264. }
  265.  
  266. #else
  267. /*******************************************************************************
  268. ** DoBind
  269. ********************************************************************************/
  270.  
  271. OSStatus DoBind(int epNum, int qlen)
  272. {
  273.     TEndpoint*    ep = gEp[epNum];
  274.     OSStatus    err;
  275.     TBind*        retBind = new TBind;
  276.     
  277.     if ( retBind == NULL )
  278.     {
  279.         DebugStr("\pADSPSample: DoBind, can not allocate TBind.");
  280.         return -1;
  281.     }
  282.     TBind reqBind;
  283.     
  284.     reqBind.addr.len    = 0;
  285.     reqBind.qlen        = qlen;
  286.  
  287.     retBind->addr.buf        = (UInt8*)&gAddr[epNum];
  288.     retBind->addr.maxlen    = sizeof(gAddr[epNum]);
  289.     
  290.     fprintf(stderr, "Issuing Bind(%d)\n", epNum);
  291.     err = ep->Bind(&reqBind, retBind);
  292.     if ( err != kOTNoError )
  293.     {
  294.         fprintf(stderr, "Bind(%d) fails with %d\n", epNum, err);
  295.         delete retBind;
  296.     }
  297.     return err;
  298. }
  299. #endif
  300. /*******************************************************************************
  301. ** DoConnect
  302. ********************************************************************************/
  303.  
  304. OSStatus DoConnect(int epNum, DDPAddress* dest)
  305. {
  306.     TEndpoint* ep = gEp[epNum];
  307.     //
  308.     // Allocate memory to hold a TCall structure and full ddp addresses
  309.     //
  310.     UInt8* p = new UInt8[sizeof(TCall) + kDDPAddressLength];
  311.     
  312.     TCall* reqCall = (TCall*)p;
  313.     
  314.     reqCall->addr.buf    = (UInt8*)(p + sizeof(TCall));
  315.     reqCall->addr.len    = kDDPAddressLength;
  316.     reqCall->opt.len    = 0;
  317.     reqCall->udata.len    = 0;
  318.     
  319.     if ( dest == NULL )                    // Need to ask about address
  320.     {
  321.         int net, node, socket;
  322.         
  323.         do
  324.         {
  325.             fprintf(stderr, "Enter the target address in Hex (net node socket):\n");
  326.             scanf("%x %x %x", &net, &node, &socket);
  327.         } while ( socket <= 0 || socket >= 256 || node <= 0 || node >= 256 );
  328.         
  329.         fprintf(stderr, "Connecting to net $%04X, node $%02X, socket $%02X\n",
  330.                         net, node, socket);
  331.         ((DDPAddress*)reqCall->addr.buf)->
  332.             Init((UInt16)net, (UInt8)node, (UInt8)socket);
  333.     }
  334.     else
  335.     {
  336.         ((DDPAddress*)reqCall->addr.buf)->Init(*dest);
  337.     }
  338.     
  339.     fprintf(stderr, "Issuing Connect(%d)\n", epNum);
  340.     OSStatus err = ep->Connect(reqCall, NULL);
  341.     
  342.     if ( err != kOTNoDataErr )
  343.     {
  344.         fprintf(stderr, "Connect(%d) returns %d instead of kOTNoDataErr\n", epNum, err);
  345.         delete p;
  346.         return -1;
  347.     }
  348.     return kOTNoError;
  349. }
  350.  
  351. /*******************************************************************************
  352. ** DoListen
  353. ********************************************************************************/
  354.  
  355. OSStatus DoListen(int epNum)
  356. {
  357.     TEndpoint*    ep = gEp[epNum];
  358.     OSStatus    err = kOTNoError;
  359.     TCall        lCall;
  360.     
  361.     lCall.addr.buf        = (UInt8*)&gAddr[epNum + kMaxEndpoints];
  362.     lCall.addr.maxlen    = sizeof(gAddr[0]);
  363.     lCall.opt.maxlen    = 0;
  364.     lCall.udata.maxlen    = 0;
  365.  
  366.     err = ep->Listen(&lCall);
  367.     if ( err == kOTNoDataErr || err == kOTStateChangeErr )
  368.         return kOTNoError;
  369.         
  370.     if ( err < 0 )
  371.     {
  372.         fprintf(stderr, "Listen(%d) failed with %d\n", epNum, err);
  373.         return err;
  374.     }
  375.     
  376.     fprintf(stderr, "Listen(%d) received request from ", epNum);
  377.     ShowDDPAddress(&gAddr[epNum + kMaxEndpoints]);
  378.     fprintf(stderr, "\n");
  379.  
  380.     if ( gEpFlags[epNum] & (kDoAcceptFlag | kDoHandOffFlag) )
  381.     {
  382.         Boolean handOff = ( 0!= (gEpFlags[epNum] & kDoHandOffFlag));
  383.         TCall* call = new TCall;
  384.         
  385.         if ( call == NULL )
  386.             return kOTNoError;
  387.         gEpFlags[epNum] &= ~(kDoAcceptFlag | kDoHandOffFlag); // To prevent doing it again
  388.         call->opt.len    = 0;
  389.         call->udata.len    = 0;
  390.          call->addr.len    = 0;
  391.         call->sequence = lCall.sequence;    
  392.         int acceptNum = handOff ? 2 : epNum;
  393.         fprintf(stderr, "Issuing Accept(%d) to accept connection\n", acceptNum);
  394.     
  395.         err = ep->Accept(gEp[acceptNum], call);
  396.         if (err)
  397.         {
  398.             fprintf(stderr, "Accept(%d) fails with %d\n", acceptNum, err);
  399.             delete call;
  400.         }
  401.     }
  402.     else if ( gEpFlags[epNum] & kDoRejectFlag )
  403.     {
  404.         gEpFlags[epNum] &= ~kDoRejectFlag; // To prevent doing it again
  405.         fprintf(stderr, "Issuing SndDisconnect(%d) to reject connection\n", epNum);
  406.         err = ep->SndDisconnect(&lCall);
  407.         if ( err != kOTNoError )
  408.             fprintf(stderr, "SndDisconnect(%d) fails with %d\n", epNum, err);
  409.     }
  410.     return err;
  411. }
  412.  
  413. /*******************************************************************************
  414. ** DoGetProtAddr
  415. ********************************************************************************/
  416.  
  417. OSStatus DoGetProtAddr(int epNum)
  418. {
  419.     TEndpoint*    ep = gEp[epNum];
  420.     UInt8*        p = new UInt8[2 * (sizeof(TBind) + kDDPAddressLength)];
  421.     
  422.     TBind* remBind = (TBind*)p;
  423.     TBind* locBind = (TBind*)(p + sizeof(TBind) + kDDPAddressLength);
  424.     
  425.     remBind->addr.buf        = p + sizeof(TBind);
  426.     remBind->addr.maxlen    = kDDPAddressLength;
  427.     
  428.     locBind->addr.buf        = p + sizeof(TBind) * 2 + kDDPAddressLength;
  429.     locBind->addr.maxlen    = kDDPAddressLength;
  430.  
  431.     fprintf(stderr, "Issuing GetProtAddress(%d)\n", epNum);
  432.     
  433.     OSStatus err = ep->GetProtAddress(locBind, remBind);
  434.     
  435.     if ( err == kOTNotSupportedErr )
  436.     {
  437.         fprintf(stderr, "GetProtAddress(%d) is not supported!\n", epNum);
  438.         err = kOTNoError;
  439.     }
  440.     else if ( err != kOTNoError )
  441.     {
  442.         fprintf(stderr, "GetProtAddress(%d) failed with %d\n", epNum, err);
  443.         delete p;
  444.     }
  445.     return err;
  446. }
  447.  
  448. /*******************************************************************************
  449. ** CreateEndpoint
  450. ********************************************************************************/
  451.  
  452. TEndpoint* CreateEndpoint(OSStatus* errP, int refNum)
  453. {
  454.     TEndpoint* ep;
  455.  
  456.     ep = OTOpenEndpoint(OTCreateConfiguration(kADSPName), 0, NULL, errP);
  457.  
  458.     if ( ep == NULL || *errP != kOTNoError )
  459.     {
  460.         fprintf(stderr,"ERROR: open of ADSP Endpoint failed.\n");
  461.         return NULL;
  462.     }
  463.  
  464.     do
  465.     {
  466.         ep->SetSynchronous();
  467.         //
  468.         // Install notifier we're going to use for testing
  469.         //
  470.         *errP = ep->InstallNotifier(&UniversalEventHandler, (void*)(refNum+1));
  471.         if ( *errP != kOTNoError )
  472.         {
  473.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", *errP);
  474.             break;
  475.         }
  476.         //
  477.         // Have to do this until the autopush stuff works right.
  478.         //
  479.         ep->Sync();
  480.         return ep;
  481.         
  482.     } while (false);
  483.     
  484.     if ( ep != NULL )
  485.         ep->Close();
  486.     
  487.     return NULL;
  488. }
  489.  
  490. /*******************************************************************************
  491. ** CheckEndpointState
  492. ********************************************************************************/
  493.  
  494. OSStatus CheckEndpointState(int epNum)
  495. {
  496.     OSStatus    err        = kOTNoError;
  497.     TEndpoint*    ep        = gEp[epNum];
  498.     UInt16        flags    = gEpFlags[epNum];
  499.     
  500.     OTResult state = ep->GetEndpointState();
  501.  
  502.     //
  503.     // Hmm. Things in progress. They will eventually complete.
  504.     //
  505.     if ( state == kOTStateChangeErr )
  506.         return kOTNoError;
  507.         
  508.     if ( state < 0 )                    // Got an error from GetEndpoint State
  509.     {
  510.         fprintf(stderr, "GetEndpointState(%d) fails with %d\n", epNum, state);
  511.         return state;
  512.     }
  513.  
  514.     if  ( state != gEpStates[epNum] )        // Detected state change.
  515.     {
  516.         gEpStates[epNum] = state;
  517.         fprintf(stderr, "State change on endpoint #%d to ", epNum);
  518.         ShowEndpointState(ep, "");
  519.     }
  520.     
  521.     //
  522.     // Based on the current state, we may want to do something...
  523.     //
  524.     switch ( state )
  525.     {
  526.         case T_UNBND:
  527.             if ( flags & kDoBindFlag )
  528.             {
  529.                 gEpFlags[epNum] &= ~kDoBindFlag;            // To prevent doing it again
  530.                 return DoBind(epNum, (epNum == 1) ? 1 : 0);
  531.             }
  532.             break;
  533.             
  534.         case T_IDLE:
  535.             if ( gDoingTearDown )
  536.             {
  537.                 fprintf(stderr, "Issuing Unbind(%d)\n", epNum);
  538.                 err = ep->Unbind();
  539.                 if ( err == kOTStateChangeErr || err == kOTOutStateErr )
  540.                     err = kOTNoError;
  541.                 else if ( err != kOTNoError )
  542.                     fprintf(stderr, "Unbind(%d) fails with %d\n", epNum, err);
  543.             }
  544.             else if ( flags & kDoProtAddrAfterBind )
  545.             {
  546.                 gEpFlags[epNum] &= ~kDoProtAddrAfterBind; // To prevent doing it again
  547.                 err = DoGetProtAddr(epNum);
  548.             }
  549.             else
  550.             {
  551.                 if ( flags & kDoConnectFlag )
  552.                 {
  553.                     gEpFlags[epNum] &= ~kDoConnectFlag; // To prevent doing it again
  554.                     if ( gEpFlags[epNum] & kDoSelfSend )
  555.                         err = DoConnect(epNum, &gAddr[epNum + 1]);
  556.                     else
  557.                         err = DoConnect(epNum, NULL);
  558.                 }
  559.             }
  560.             break;
  561.             
  562.         case T_OUTCON:
  563.             break;
  564.             
  565.         case T_INCON:
  566.             break;
  567.         
  568.         case T_DATAXFER:
  569.             if ( gDoingTearDown )
  570.             {
  571.                 fprintf(stderr, "Issuing SndOrderlyDisconnect(%d)\n", epNum);
  572.                 err = ep->SndOrderlyDisconnect();
  573.                 if (err != kOTNoError )
  574.                 {
  575.                     if ( err == kOTLookErr )
  576.                     {
  577.                         fprintf(stderr,
  578.                             "SndOrderlyDisconnect(%d) returns with kLook\n", epNum);
  579.                         err = kOTNoError;
  580.                     }
  581.                     else
  582.                         fprintf(stderr,
  583.                             "SndOrderlyDisconnect(%d) fails with %d\n", epNum, err);
  584.                 }
  585.             }
  586.             else if ( flags & kDoProtAddrAfterConnect )
  587.             {
  588.                 gEpFlags[epNum] &= ~kDoProtAddrAfterConnect; // To prevent doing it again
  589.                 err = DoGetProtAddr(epNum);
  590.             }
  591.             else
  592.             {
  593.                 err = DoRead(epNum);
  594. #if 1
  595.                 if ( err == kOTNoDataErr )                // Only send if we read nothing
  596.                     err = DoSend(epNum, false, false);
  597. #else
  598.                 if ( err == kOTNoDataErr || err == kOTLookErr )
  599.                     err = kOTNoError;
  600. #endif
  601.             }
  602.             break;
  603.             
  604.         case T_UNINIT:
  605.             fprintf(stderr,
  606.                 "GetEndpointState(%d) returns unexpected state T_UNINIT\n", epNum);
  607.             err = -1;
  608.  
  609.         case T_OUTREL:                // We're waiting for a T_ORDREL event coming in.
  610.                                     // Must continue to read any incoming data
  611.                 err = DoRead(epNum);
  612.                 if ( err == kOTNoDataErr || err == kOTLookErr )
  613.                     err = kOTNoError;
  614.             break;
  615.  
  616.         case T_INREL:
  617.             fprintf(stderr, "Issuing SndOrderlyDisconnect(%d)\n", epNum);
  618.             err = ep->SndOrderlyDisconnect();
  619.             if ( err != kOTNoError )
  620.             {
  621.                 if ( err == kOTLookErr )
  622.                 {
  623.                     fprintf(stderr,
  624.                         "SndOrderlyDisconnect(%d) returns with kOTLookErr\n", epNum);
  625.                     err = kOTNoError;
  626.                 }
  627.                 else
  628.                     fprintf(stderr,
  629.                         "SndOrderlyDisconnect(%d) fails with %d\n", epNum, err);
  630.             }
  631.             break;
  632.  
  633.         default:
  634.             fprintf(stderr,
  635.                 "GetEndpointState(%d) returns unknown state %d\n", epNum, state);
  636.             err = -1;
  637.             break;
  638.     };
  639.     
  640.     return err;
  641. }
  642.  
  643. /*******************************************************************************
  644. ** PollEventList
  645. ********************************************************************************/
  646.  
  647. OSStatus PollEventList()
  648. {
  649.     OSStatus err = kOTNoError;
  650.     
  651.     while ( gEventList.fHead != NULL )
  652.     {
  653.         OTLink* link = OTReverseList(OTLIFOStealList(&gEventList));
  654.  
  655.         while ( link != NULL )
  656.         {
  657.             TOTEventItem*    item = OTGetLinkObject(link, TOTEventItem, fLink);
  658.             OTResult        result = item->fResult;
  659.             void*            cookie = item->fCookie;
  660.             int                epNum  = (int)item->fRef - 1;
  661.                 
  662.             link = link->fNext;
  663.         
  664.             if ( epNum < 0 || epNum > 2 )
  665.             {
  666.                 delete item;
  667.                 continue;
  668.             }
  669.     
  670.             TEndpoint* ep = gEp[epNum];
  671.             
  672.             switch ( item->fCode )
  673.             {
  674.                 case T_BINDCOMPLETE:
  675.                 {
  676.                     TBind* bindRet = (TBind*)item->fCookie;
  677.                     if ( result != kOTNoError )
  678.                     {
  679.                         fprintf(stderr, "Bind(%d) failed with %d\n", epNum, result);
  680.                         err = (OSStatus)result;
  681.                     }
  682.                     else
  683.                     {
  684.                         fprintf(stderr, "Endpoint #%d bound to ", epNum);
  685.                         ShowDDPAddress(&gAddr[epNum]);
  686.                         fprintf(stderr, "\n");
  687.                     }
  688.                     delete bindRet;
  689.                     break;
  690.                 }
  691.                 
  692.                 case T_UNBINDCOMPLETE:
  693.                     if  (result != kOTNoError )
  694.                     {
  695.                         fprintf(stderr, "Unbind(%d) failed with %d\n", epNum, result);
  696.                         err = 0;            // Ignore errors from unbind
  697.                     }
  698.                     break;
  699.                     
  700.                 case T_DISCONNECT:
  701.                 {
  702.                     fprintf(stderr, "T_DISCONNECT event on endpoint #%d\n", epNum);
  703.                     TBind* bindReq = (TBind*)item->fCookie;
  704.                     
  705.                     if ( bindReq != NULL )            // A connect is rejected
  706.                     {
  707.                         fprintf(stderr, "Connect(%d) rejected\n", epNum);
  708.                     }
  709.                     fprintf(stderr, "Issuing RcvDisconnect(%d)\n", epNum);
  710.                     err = ep->RcvDisconnect(NULL);
  711.                     if ( err != kOTNoError )
  712.                     {
  713.                         fprintf(stderr, "RcvDisconnect(%d) fails with %d\n", epNum, err);
  714.                     }
  715.                     break;
  716.                 }
  717.                 
  718.                 case T_ORDREL:
  719.                 {
  720.                     fprintf(stderr, "T_ORDREL event on endpoint #%d\n", epNum);
  721.                     fprintf(stderr, "Issuing RcvOrderlyDisconnect(%d)\n", epNum);
  722.                     err = ep->RcvOrderlyDisconnect();
  723.                     if ( err != kOTNoError )
  724.                     {
  725.                         fprintf(stderr, "RcvOrderlyDisconnect(%d) fails with %d\n", epNum, err);
  726.                     }
  727.                     break;
  728.                 }
  729.                 
  730.                 case T_CONNECT:
  731.                 {
  732.                     TCall* reqCall = (TCall*)item->fCookie;
  733.                     delete reqCall;
  734.                     
  735.                     if ( result != kOTNoError )
  736.                     {
  737.                         fprintf(stderr, "Connect(%d) failed with %d\n", epNum, result);
  738.                         err = (OSStatus)result;
  739.                     }
  740.                     else
  741.                     {
  742.                         TCall retCall;
  743.                         
  744.                         retCall.addr.buf     = (UInt8*)&gAddr[epNum + kMaxEndpoints];
  745.                         retCall.addr.maxlen    = kDDPAddressLength;
  746.                         retCall.opt.len        = 0;
  747.                         retCall.opt.maxlen    = 0;
  748.                         retCall.udata.len    = 0;
  749.                         retCall.udata.maxlen = 0;
  750.     
  751.                         fprintf(stderr, "Connect(%d) completes with no error\n", epNum);
  752.                         fprintf(stderr, "Issuing RcvConnect(%d)\n", epNum);
  753.                         err = ep->RcvConnect(&retCall);
  754.                         if ( err != kOTNoError )
  755.                         {
  756.                             fprintf(stderr, "RcvConnect(%d) fails with %d\n", epNum, err);
  757.                         }
  758.                         else
  759.                         {
  760.                             fprintf(stderr, "Endpoint #%d connected to ", epNum);
  761.                             ShowDDPAddress(&gAddr[epNum + kMaxEndpoints]);
  762.                             fprintf(stderr, "\n");
  763.                         }
  764.                     }
  765.                     break;
  766.                 }
  767.                 
  768.                 case T_ACCEPTCOMPLETE:
  769.                 {
  770.                     if ( result == kOTNoError )
  771.                         fprintf(stderr, "Accept(%d) completes with no error\n", epNum);
  772.                     else
  773.                     {
  774.                         fprintf(stderr, "Accept(%d) fails with %d\n", epNum, result);
  775.                         err = (OSStatus)result;
  776.                     }
  777.                     break;
  778.                 }
  779.                 
  780.                 case T_PASSCON:
  781.                     fprintf(stderr, "T_PASSCON event on Ep #%d\n", epNum);
  782.                     break;
  783.                 
  784.                 case T_GETPROTADDRCOMPLETE:
  785.                 {
  786.                     TBind* remBind = (TBind*)item->fCookie;
  787.                     TBind* locBind = (TBind*)((UInt8*)remBind +
  788.                                               sizeof(TBind) + kDDPAddressLength);
  789.                                         
  790.                     if ( result == kOTNoError )
  791.                     {
  792.                         fprintf(stderr, "GetProtAddress(%d) completes with no error\n", epNum);
  793.                         fprintf(stderr, "  LocAddr = ");
  794.                         ShowDDPAddress((DDPAddress*)locBind->addr.buf);
  795.                         fprintf(stderr, "\n");
  796.                         fprintf(stderr, "  RemAddr = ");
  797.                         ShowDDPAddress((DDPAddress*)remBind->addr.buf);
  798.                         fprintf(stderr, "\n");
  799.                         //
  800.                         // Save our local address in global array
  801.                         //
  802.                         gAddr[epNum].Init(*(DDPAddress*)locBind->addr.buf);
  803.                     }
  804.                     else if ( result == kOTNotSupportedErr )
  805.                     {
  806.                         fprintf(stderr, "GetProtAddress(%d) is not supported!\n", epNum, result);
  807.                         err = kOTNoError;
  808.                     }
  809.                     else
  810.                     {
  811.                         fprintf(stderr, "GetProtAddress(%d) fails with %d\n", epNum, result);
  812.                         err = (OSStatus)result;
  813.                     }
  814.                     delete remBind;
  815.                     break;
  816.                 }
  817.                 
  818.                 case T_DISCONNECTCOMPLETE:
  819.                 {
  820.                     TDiscon* discon = (TDiscon*)item->fCookie;
  821.                     
  822.                     if ( result == kOTNoError )
  823.                     {
  824.                         fprintf(stderr, "SndDisconnect(%d) completes with no error\n", epNum);
  825.                     }
  826.                     else
  827.                     {
  828.                         fprintf(stderr, "SndDisconnect(%d) fails with %d\n", epNum, result);
  829.                         err = (OSStatus)result;
  830.                     }
  831.                     delete discon;
  832.                     break;
  833.                 }
  834.                 
  835.                 case T_LISTEN:
  836.                 {
  837.                     err = DoListen(epNum);
  838.                     break;
  839.                 }
  840.     
  841.                 case T_DATA:
  842.                     //fprintf(stderr, "T_DATA event on Ep #%d\n", epNum);
  843.                     // Fall into next case    
  844.                     
  845.                 case T_EXDATA:
  846.                     if ( item->fCode == T_EXDATA )
  847.                         fprintf(stderr, "T_EXDATA event on Ep #%d\n", epNum);
  848.                     break;
  849.                     
  850.                 case T_GODATA:
  851.                     gEpFlags[epNum] &= ~kSendFlowedFlag;
  852.                     fprintf(stderr, "GoData event on Ep #%d\n", epNum);
  853.                     break;
  854.                 
  855.                 case T_GOEXDATA:
  856.                     gEpFlags[epNum] &= ~kSendExFlowedFlag;
  857.                     fprintf(stderr, "GoExData event on Ep #%d\n", epNum);
  858.                     break;
  859.                     
  860.                 default:
  861.                     fprintf(stderr, "Unknown event in event record, %08LX\n", item->fCode);
  862.                     break;
  863.             }
  864.             delete item;
  865.         }
  866.     }
  867.     return err;
  868. }
  869.  
  870. /*******************************************************************************
  871. ** DoTest
  872. ********************************************************************************/
  873.  
  874. void DoTest()
  875. {
  876.     OSStatus    err = kOTNoError;
  877.     TEndpoint*    ep = NULL;
  878.     Boolean        quit = false;
  879.     
  880.     gByteCtr = 0;
  881.     gDotCtr = 0;
  882.     
  883.     int epNum;
  884.     
  885.     //
  886.     // Initialize address variables
  887.     //
  888.     for ( epNum = 0 ; epNum < (2 * kMaxEndpoints) ; epNum++ )
  889.     {
  890.         gAddr[epNum].Init(0, 0, 0);
  891.     }
  892.  
  893.     do
  894.     {
  895.         //
  896.         // Create the endpoints
  897.         //
  898.         for ( epNum = 0 ; epNum < kMaxEndpoints ; epNum++ )
  899.         {
  900.             gEp[epNum] = CreateEndpoint(&err, epNum);
  901.             if ( gEp[epNum] == NULL || err != kOTNoError )
  902.                 break;
  903.             gEp[epNum]->SetAsynchronous();        // Ensure endpoint is async
  904.             gEp[epNum]->SetNonBlocking();        // Ensure endpoint is non-blocking
  905.         }
  906.         if ( err != kOTNoError )
  907.             break;
  908.         
  909.         //
  910.         // Dump out the Endpoint Info for one of the endpoints.
  911.         // Must set it in synchronous mode first, because we want to print out
  912.         // the results.
  913.         //
  914.         gEp[0]->SetSynchronous();
  915.         ShowFullEndpointData(gEp[0]);
  916.         gEp[0]->SetAsynchronous();
  917.  
  918.         //
  919.         // Ask user what to do
  920.         //
  921.         gTestNum = -2;
  922.         
  923.         while ( gTestNum < 0 || gTestNum > 7  )
  924.         {
  925.             fprintf(stderr, "\nChoose Test:\n");
  926.             fprintf(stderr, "    0) QUIT, QUIT, QUIT\n");
  927.             fprintf(stderr, "    1) Connect to remote node\n");
  928.             fprintf(stderr, "    2) Listen and accept connection from remote node\n");
  929.             fprintf(stderr, "    3) Listen and reject connection from remote node\n");
  930.             fprintf(stderr, "    4) Listen and handoff connection from remote node\n");
  931.             fprintf(stderr, "    5) Connect/Listen/Accept self-send\n");
  932.             fprintf(stderr, "    6) Connect/Listen/Reject self-send\n");
  933.             fprintf(stderr, "    7) Connect/Listen/handoff self-send\n");
  934.             scanf("%x", &gTestNum);
  935.         }
  936.         
  937.         //
  938.         // Set a bunch of flags so that the various other parts of the program
  939.         // know what to do.
  940.         //
  941.         switch ( gTestNum )
  942.         {
  943.             case 0:                    // Quit
  944.                 quit = true;
  945.                 break;
  946.                 
  947.             case 1:                    // Connect to remote node
  948.                 gEpFlags[0] = kDoBindFlag | kDoProtAddrAfterBind | 
  949.                                         kDoConnectFlag | kDoProtAddrAfterConnect;
  950.                 break;
  951.  
  952.             case 2:                    // Listen and accept connection from remote node
  953.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag | 
  954.                                 kDoAcceptFlag | kDoProtAddrAfterConnect;
  955.                 break;
  956.  
  957.             case 3:                    // Listen and reject connection from remote node
  958.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag | 
  959.                                 kDoRejectFlag | kDoProtAddrAfterConnect;
  960.                 break;
  961.  
  962.             case 4:                    // Listen and handoff connection from remote node
  963.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag | 
  964.                                 kDoHandOffFlag | kDoProtAddrAfterConnect;
  965.                 break;
  966.  
  967.             case 5:                    // Connect/Listen/Accept self-send
  968.                 gEpFlags[0] = kDoBindFlag | kDoProtAddrAfterBind | kDoConnectFlag | 
  969.                                 kDoSelfSend | kDoProtAddrAfterConnect;
  970.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag | 
  971.                                 kDoAcceptFlag | kDoSelfSend | kDoProtAddrAfterConnect;
  972.                 break;
  973.  
  974.             case 6:                    // Connect/Listen/Reject self-send
  975.                 gEpFlags[0] = kDoBindFlag | kDoProtAddrAfterBind | kDoConnectFlag | 
  976.                                 kDoSelfSend | kDoProtAddrAfterConnect;
  977.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag | 
  978.                                 kDoRejectFlag | kDoSelfSend | kDoProtAddrAfterConnect;
  979.                 break;
  980.  
  981.             case 7:                    // Connect/Listen/HandOff self-send
  982.                 gEpFlags[0] = kDoBindFlag | kDoProtAddrAfterBind | /*kDoConnectFlag | */
  983.                                 kDoSelfSend | kDoProtAddrAfterConnect;
  984.                 gEpFlags[1] = kDoBindFlag | kDoProtAddrAfterBind | kDoListenFlag |
  985.                                 kDoHandOffFlag | kDoSelfSend | kDoProtAddrAfterConnect;
  986.                 break;
  987.         };
  988.  
  989.         //
  990.         // Now get things rolling!
  991.         // The CheckEndpointState looks at an endpoint's current state, and then based
  992.         // on the flags set above, causes the endpoint do do things.
  993.         // This will sit here until the user clicks the mouse.
  994.         //
  995.         while ( !Button() && !quit )
  996.         {
  997.             err = PollEventList();
  998.             if ( err != kOTNoError )
  999.                 break;
  1000.             for ( epNum = 0 ; epNum < kMaxEndpoints ; epNum++ )
  1001.             {
  1002.                 err = CheckEndpointState(epNum);
  1003.                 if ( err != kOTNoError )
  1004.                     break;
  1005.             }
  1006.             if ( err != kOTNoError )
  1007.                 break;
  1008.             OTIdle();
  1009.         }
  1010.         while ( Button() && !quit )            // Let go of the dang thing!
  1011.             ;
  1012.         
  1013.         //
  1014.         // Wait for everything to shut down
  1015.         //
  1016.         fprintf(stderr, "Waiting for all endpoints to unbind...\n");
  1017.         gDoingTearDown = true;
  1018.  
  1019.         OTTimeStamp    stamp;
  1020.         
  1021.         OTGetTimeStamp(&stamp);
  1022.         
  1023.         while ( !Button() ) 
  1024.         {
  1025.             err = PollEventList();
  1026.             if ( err != kOTNoError )
  1027.                 break;
  1028.             int keepWaiting = false;
  1029.             
  1030.             for ( epNum = 0 ; epNum < kMaxEndpoints ; epNum++ )
  1031.             {
  1032.                 err = CheckEndpointState(epNum);
  1033.                 if ( err != kOTNoError )
  1034.                     break;
  1035.                 OTResult state = gEp[epNum]->GetEndpointState();
  1036.                 if ( state > 0 && state != T_UNBND )
  1037.                     keepWaiting = true;
  1038.             }
  1039.             if ( !keepWaiting && OTElapsedMilliseconds(&stamp) > 2000 )
  1040.                 break;
  1041.             OTIdle();
  1042.         }
  1043.  
  1044.     } while ( false );
  1045.  
  1046.     //
  1047.     // Clean up all the endpoints we allocated
  1048.     //
  1049.     for ( epNum = 0 ; epNum < kMaxEndpoints ; epNum++ )
  1050.     {
  1051.         if ( gEp[epNum] != NULL )
  1052.         {
  1053.             gEp[epNum]->RemoveNotifier();
  1054.             gEp[epNum]->Close();
  1055.             if ( err != kOTNoError )
  1056.                 fprintf(stderr, "ERROR: CloseEndpoint(gEp[%d]) returned %d\n", epNum, err);
  1057.         }
  1058.     }
  1059.     //
  1060.     // Clean up any unread event structures
  1061.     //
  1062.     {
  1063.         OTLink* link;
  1064.         while ( (link = gEventList.fHead) != NULL )
  1065.         {
  1066.             TOTEventItem* item = OTGetLinkObject(link, TOTEventItem, fLink);
  1067.             gEventList.fHead = link->fNext;
  1068.             delete item;
  1069.         }
  1070.     }
  1071. }
  1072.  
  1073. /*******************************************************************************
  1074. ** Initialize Open Transport and call DoTest function
  1075. ********************************************************************************/
  1076.  
  1077. main(int, char**) 
  1078. {
  1079.     InitGraf(&qd.thePort);        // initialize quickdraw so we can use regions
  1080.  
  1081.     fprintf(stderr, "ADSPSample showing usage of ADSP.\n\n");
  1082.     //
  1083.     // Initialize Open Transport - we're an application, so pass "true"
  1084.     //
  1085.     InitOpenTransport();
  1086.     //
  1087.     // Run the test
  1088.     //
  1089.     DoTest();
  1090.     //
  1091.     // Close Open Transport.
  1092.     // Not strictly necessary since it patches _ExitToShell and will
  1093.     // clean us up anyway.
  1094.     //
  1095.     CloseOpenTransport();
  1096.     
  1097.     fprintf(stderr, "\n\nDone\n");
  1098.         
  1099.     return 0;
  1100. };
  1101.  
  1102.